package com.gzc.just.play.last.war.common.registry.nacos;

import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingFactory;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.listener.NamingEvent;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.gzc.just.play.last.war.common.distributed.ServiceInstance;
import com.gzc.just.play.last.war.common.registry.ServiceDiscovery;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import jakarta.annotation.PreDestroy;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
import java.util.stream.Collectors;

/**
 * Nacos服务发现实现
 */
@Component("lastWarNacosServiceDiscovery")
public class NacosServiceDiscovery implements ServiceDiscovery {
    
    private static final Logger logger = LoggerFactory.getLogger(NacosServiceDiscovery.class);
    
    private NamingService namingService;
    
    private final Map<String, Consumer<List<ServiceInstance>>> listeners = new ConcurrentHashMap<>();
    
    @Value("${spring.cloud.nacos.discovery.server-addr:127.0.0.1:8848}")
    private String serverAddr;
    
    @Value("${spring.cloud.nacos.discovery.namespace:}")
    private String namespace;
    
    @Value("${spring.cloud.nacos.discovery.group:DEFAULT_GROUP}")
    private String group;
    
    @Value("${spring.cloud.nacos.discovery.enabled:true}")
    private boolean enabled;
    
    @Value("${nacos.service.register.ip:127.0.0.1}")
    private String nacosRegisterIp;
    
    /**
     * 初始化Nacos命名服务
     */
    private void initNamingService() throws NacosException {
        if (!enabled) {
            logger.info("Nacos service discovery is disabled");
            return;
        }
        
        if (namingService == null) {
            Properties properties = new Properties();
            properties.put("serverAddr", serverAddr);
            if (namespace != null && !namespace.isEmpty()) {
                properties.put("namespace", namespace);
            }
            namingService = NamingFactory.createNamingService(properties);
            logger.info("Nacos naming service initialized for discovery: serverAddr={}, namespace={}", serverAddr, namespace);
        }
    }
    
    @Override
    public List<ServiceInstance> getInstances(String serviceName) throws Exception {
        if (!enabled) {
            logger.debug("Nacos discovery disabled, returning empty list");
            return List.of();
        }
        
        initNamingService();
        
        List<Instance> instances = namingService.getAllInstances(serviceName, group);
        return instances.stream()
                .map(this::convertToServiceInstance)
                .collect(Collectors.toList());
    }
    
    @Override
    public List<ServiceInstance> getHealthyInstances(String serviceName) throws Exception {
        if (!enabled) {
            logger.debug("Nacos discovery disabled, returning empty list");
            return List.of();
        }
        
        initNamingService();
        
        List<Instance> instances = namingService.selectInstances(serviceName, group, true);
        return instances.stream()
                .map(this::convertToServiceInstance)
                .collect(Collectors.toList());
    }
    
    @Override
    public void subscribe(String serviceName, Consumer<List<ServiceInstance>> listener) throws Exception {
        if (!enabled) {
            logger.debug("Nacos discovery disabled, skip subscription");
            return;
        }
        
        initNamingService();
        
        listeners.put(serviceName, listener);
        
        namingService.subscribe(serviceName, group, event -> {
            if (event instanceof NamingEvent) {
                NamingEvent namingEvent = (NamingEvent) event;
                List<ServiceInstance> instances = namingEvent.getInstances().stream()
                        .map(this::convertToServiceInstance)
                        .collect(Collectors.toList());
                
                Consumer<List<ServiceInstance>> callback = listeners.get(serviceName);
                if (callback != null) {
                    callback.accept(instances);
                }
                
                logger.debug("Service {} instances updated: count={}", serviceName, instances.size());
            }
        });
        
        logger.info("Subscribed to service: {}", serviceName);
    }
    
    @Override
    public void unsubscribe(String serviceName) throws Exception {
        if (!enabled || namingService == null) {
            return;
        }
        
        namingService.unsubscribe(serviceName, group, event -> {});
        listeners.remove(serviceName);
        logger.info("Unsubscribed from service: {}", serviceName);
    }
    
    @PreDestroy
    @Override
    public void close() {
        if (namingService != null) {
            try {
                namingService.shutDown();
                listeners.clear();
                logger.info("Nacos discovery service closed");
            } catch (Exception e) {
                logger.error("Error closing Nacos discovery service", e);
            }
        }
    }
    
    /**
     * 将Nacos Instance转换为ServiceInstance
     */
    private ServiceInstance convertToServiceInstance(Instance instance) {
        ServiceInstance serviceInstance = new ServiceInstance();
        serviceInstance.setInstanceId(instance.getInstanceId());
        serviceInstance.setServiceName(instance.getServiceName());
        // 在all-in-one模式下，使用配置的IP地址而不是Nacos中注册的IP
        // 这样可以确保在同一台机器上运行多个服务实例时，使用127.0.0.1进行内部通信
        serviceInstance.setHost(nacosRegisterIp);
        serviceInstance.setPort(instance.getPort());
        serviceInstance.setScheme("tcp");
        serviceInstance.setMetadata(instance.getMetadata());
        return serviceInstance;
    }
}
